using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using Nuwanda.Common;
using Nuwanda.TfsSpotlight.Shell.Proxies.Interfaces;
using Nuwanda.TfsSpotlight.Shell.Services.Interfaces;
using StructureMap.Configuration.DSL;
using ObjectFactory=StructureMap.ObjectFactory;

namespace Nuwanda.TfsSpotlight.Shell
{
    public abstract class ApplicationController : IApplicationController
    {
        public ShellView ShellView { get; private set; }

        public abstract string ApplicationName { get; }
        public abstract Icon ApplicationIcon { get; }
        public bool IsBeta { get; set; }

        #region Services

        private IMenuService _menuService;
        protected IMenuService MenuService
        {
            [DebuggerStepThrough]
            get
            {
                if (this._menuService == null)
                {
                    this._menuService = ObjectFactory.GetInstance<IMenuService>();
                }

                return this._menuService;
            }
        }

        private IMonitService _monitService;
        protected IMonitService MonitService
        {
            [DebuggerStepThrough]
            get
            {
                if (this._monitService == null)
                {
                    this._monitService = ObjectFactory.GetInstance<IMonitService>();
                }

                return this._monitService;
            }
        }

        private IIsolatedStorageService _isolatedStorageService;
        protected IIsolatedStorageService IsolatedStorageService
        {
            [DebuggerStepThrough]
            get
            {
                if (this._isolatedStorageService == null)
                {
                    this._isolatedStorageService = ObjectFactory.GetInstance<IIsolatedStorageService>();
                }

                return this._isolatedStorageService;
            }
        }

        private IUpdateService _updateService;
        protected IUpdateService UpdateService
        {
            [DebuggerStepThrough]
            get
            {
                if (this._updateService == null)
                {
                    this._updateService = ObjectFactory.GetInstance<IUpdateService>();
                }

                return this._updateService;
            }
        }

        private ISideBar _leftSideBar;
        protected ISideBar LeftSideBar
        {
            [DebuggerStepThrough]
            get
            {
                if (this._leftSideBar == null)
                {
                    this._leftSideBar = ObjectFactory.GetNamedInstance<ISideBar>(SideBars.Left);
                }

                return this._leftSideBar;
            }
        }

        private ISideBar _rightSideBar;
        protected ISideBar RightSidebar
        {
            [DebuggerStepThrough]
            get
            {
                if (this._rightSideBar == null)
                {
                    this._rightSideBar = ObjectFactory.GetNamedInstance<ISideBar>(SideBars.Right);
                }

                return this._rightSideBar;
            }
        }
        #endregion

        public void Initialize()
        {
            SetUpUnhandledExceptions();

            var splashView = new SplashScreenView();
            var splashPresenter = new SplashScreenPresenter(splashView);
            splashPresenter.Initialize(this.IsBeta);
            splashPresenter.FadeIn();

            this.ShellView = new ShellView {Text = this.ApplicationName, Icon = this.ApplicationIcon};
            this.ShellView.Shown += delegate { OnRun(); };
            this.ShellView.Closing += delegate(object sender, CancelEventArgs e) { e.Cancel = OnClosing(); };
            this.ShellView.Closed += delegate { OnClosed(); };

            SetUpDependencies();

            var tabStripPresenter = ObjectFactory.GetInstance<ITabStripPresenter>();
            tabStripPresenter.Initialize();

            OnInitialization();
            ApplayLayoutState(); 

            splashPresenter.FadeOut();
        }

        private void ApplayLayoutState()
        {
            var state = this.IsolatedStorageService.Load<ShellLayoutState>("ShellLayout.state");
            this.ShellView.ApplyLayoutState(state);
        }

        public void SaveLayoutSate()
        {
            var currentState = this.ShellView.GetCurrentLayoutState();
            var oldShellLayoutState = this.IsolatedStorageService.Load<ShellLayoutState>("ShellLayout.state");
            if (oldShellLayoutState != null)
            {
                if (currentState.WindowState != FormWindowState.Normal)
                {
                    currentState.Location = oldShellLayoutState.Location;
                    currentState.Size = oldShellLayoutState.Size;
                }

                if (currentState.WindowState == FormWindowState.Minimized)
                    currentState.WindowState = FormWindowState.Normal;
            }

            this.IsolatedStorageService.Save(currentState, "ShellLayout.state");
        }

        public void RestartApplication()
        {
            
        }


        public void CloseApplication()
        {
            this.ShellView.Close();
        }


        private static void SetUpUnhandledExceptions()
        {
            Application.SetUnhandledExceptionMode(UnhandledExceptionMode.Automatic);
            var unhandledExceptionPresenter = new UnhandledExceptionPresenter(new UnhandledExceptionView());
            unhandledExceptionPresenter.Initialize();
            Application.ThreadException += unhandledExceptionPresenter.HandleThreadException;
            AppDomain.CurrentDomain.UnhandledException += unhandledExceptionPresenter.HandleUnhandledException;
        }

        private void SetUpDependencies()
        {
            ObjectFactory.Configure(
                delegate(Registry registry)
                    {
                        registry.ScanAssemblies().IncludeAssembly("TfsSpotlight.Shell");

                        OnSettingDependencies(registry);

                        registry.BuildInstancesOf<IKryptonManager>()
                            .TheDefaultIs(RegistryExpressions.Object(this.ShellView.KryptonManager))
                            .AsSingletons();
                        registry.BuildInstancesOf<IMenuStrip>()
                            .TheDefaultIs(RegistryExpressions.Object(this.ShellView.MenuStrip))
                            .AsSingletons();
                        registry.BuildInstancesOf<IMenuStrip>()
                            .TheDefaultIs(RegistryExpressions.Object(this.ShellView.MenuStrip))
                            .AsSingletons();
                        registry.BuildInstancesOf<IToolStrip>()
                            .TheDefaultIs(RegistryExpressions.Object(this.ShellView.ToolStrip))
                            .AsSingletons();
                        registry.BuildInstancesOf<IStatusBar>()
                            .TheDefaultIs(RegistryExpressions.Object(this.ShellView.StatusBar))
                            .AsSingletons();
                        registry.BuildInstancesOf<IKryptonHeader>()
                            .TheDefaultIs(RegistryExpressions.Object(this.ShellView.MonitBar))
                            .AsSingletons();
                        registry.BuildInstancesOf<ISaveFileDialog>()
                            .TheDefaultIs(RegistryExpressions.Object(this.ShellView.SaveFileDialog))
                            .AsSingletons();
                        registry.AddInstanceOf(this.ShellView.LeftSideBar).WithName(SideBars.Left);
                        registry.AddInstanceOf(this.ShellView.RightSideBar).WithName(SideBars.Right);
                        registry.BuildInstancesOf<IApplicationController>()
                            .TheDefaultIs(RegistryExpressions.Object<IApplicationController>(this))
                            .AsSingletons();
                        registry.BuildInstancesOf<ITabStrip>()
                            .TheDefaultIs(RegistryExpressions.Object(this.ShellView.TabStrip))
                            .AsSingletons();
                    });
        }

        protected abstract void OnSettingDependencies(Registry registry);
        protected abstract void OnInitialization();
        protected abstract void OnRun();
        protected abstract void OnClosed();
        protected abstract bool OnClosing();
    }
}